package handler

import (
	"bufio"
	"github.com/gin-gonic/gin"
	"net/http"
	"os"
	"path/filepath"
	"starry_sky/internal/config"
	"starry_sky/internal/core"
	"starry_sky/internal/dal"
	"starry_sky/internal/model"
	"starry_sky/internal/template/code"
	"starry_sky/internal/tools"
	"starry_sky/internal/tools/logger"
	"strings"
)

func CreateOrUpdateTemplateStruct(c *gin.Context) {
	var templateStruct = model.TemplateStruct{}
	err := c.Bind(&templateStruct)
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("接受参数错误"))
		return
	}
	if templateStruct.StructName != "" {
		var count int64
		queryMap := map[string]interface{}{"struct_name": templateStruct.StructName}
		err := dal.JudgmentRepetition[model.TemplateStruct](&count, queryMap, templateStruct.ID)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体新增失败"))
			return
		}
		if count > 0 {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体名称重复，结构体新增失败"))
			return
		}
	}
	if templateStruct.ID == core.EmptyID {
		err = dal.Insert[model.TemplateStruct](&templateStruct)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体新增失败"))
			return
		}
	} else {
		tx := dal.TransactionBegin()
		// 更新主实体
		//err = dal.TransactionUpdate[model.TemplateStruct](tx, &templateStruct)
		// 比较并清空不存在的级联关系
		err = tx.Model(&templateStruct).Association("TemplateAttributes").Replace(templateStruct.TemplateAttributes)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体更新失败"))
			err = dal.TransactionRollback(tx)
			if logger.HasError(err) {
				c.JSON(http.StatusInternalServerError, core.Err.WithMsg("事务回滚失败"))
				return
			}
			return
		}
		// 更新级联实体
		//err := dal.TransactionUpdate(tx, &templateStruct.TemplateAttributes)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体属性更新失败"))
			err = dal.TransactionRollback(tx)
			if logger.HasError(err) {
				c.JSON(http.StatusInternalServerError, core.Err.WithMsg("事务回滚失败"))
				return
			}
			return
		}
		// 删除不存在的级联关系
		err = tx.Where("template_struct_id is null").Delete(&model.TemplateAttribute{}).Error
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体属性删除失败"))
			err = dal.TransactionRollback(tx)
			if logger.HasError(err) {
				c.JSON(http.StatusInternalServerError, core.Err.WithMsg("事务回滚失败"))
				return
			}
			return
		}
		// 提交事务
		err = dal.TransactionCommit(tx)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("事务提交失败"))
			return
		}
	}
	c.JSON(http.StatusOK, core.OK)
}

func FindTemplateStructById(c *gin.Context) {
	var templateStruct = model.TemplateStruct{}
	err := c.Bind(&templateStruct)
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("接受参数错误"))
		return
	}
	err = dal.FindById[model.TemplateStruct](&templateStruct, "TemplateAttributes")
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体查询失败"))
		return
	}
	c.JSON(http.StatusOK, core.OK.WithData(templateStruct))
}

func DeleteTemplateStruct(c *gin.Context) {
	var templateStruct = model.TemplateStruct{}
	err := c.Bind(&templateStruct)
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("接受参数错误"))
		return
	}
	tx := dal.TransactionBegin()
	err = tx.Where("template_struct_id = ?", templateStruct.ID).Delete(&model.TemplateAttribute{}).Error
	if err != nil {
		err := dal.TransactionRollback(tx)
		if err != nil {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("事务回滚失败"))
			return
		}
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体属性删除失败"))
		return
	}
	err = dal.TransactionDelete[model.TemplateStruct](tx, &templateStruct)
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体删除失败"))
		return
	}
	err = dal.TransactionCommit(tx)
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("事务提交失败"))
		return
	}
	c.JSON(http.StatusOK, core.OK)
}

func ListTemplateStructPage(c *gin.Context) {
	pageSupport := core.PageSupport[model.TemplateStruct]{}
	err := c.ShouldBindJSON(&pageSupport)
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("接受参数错误"))
		return
	}
	err = dal.FindPage(&pageSupport, make(map[string]any), make([]string, 0), "struct_name")
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("列表数据查询失败"))
		return
	}
	c.JSON(http.StatusOK, core.OK.WithData(pageSupport))
}

var ModelPath = "biz/model"
var DaoPath = "biz/dal"
var ServicePath = "biz/handler"

func GenerateStructForAll(c *gin.Context) {
	// 查询生成模板
	var templateStruct = model.TemplateStruct{}
	err := c.Bind(&templateStruct)
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("接受参数错误"))
		return
	}
	err = dal.FindById[model.TemplateStruct](&templateStruct, "TemplateAttributes")
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体查询失败"))
		return
	}
	if !templateStruct.GeneratState {
		err = deleteStructAll(templateStruct)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体清理失败"))
			return
		}
	}
	//生成相关文件
	err = generateStructForModel(templateStruct)
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体Model生成失败"))
		err = deleteStructAll(templateStruct)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体清理失败"))
			return
		}
		return
	}
	err = generateStructForDao(templateStruct)
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体Dao生成失败"))
		err = deleteStructAll(templateStruct)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体清理失败"))
			return
		}
		return
	}
	err = generateStructForService(templateStruct)
	if logger.HasError(err) {
		c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体Service生成失败"))
		err = deleteStructAll(templateStruct)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体清理失败"))
			return
		}
		return
	}
	if !templateStruct.GeneratState {
		var allRouter []string
		allRouter = append(allRouter, generateRouting(templateStruct))
		err = addRouter(allRouter)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("路由生成失败"))
			return
		}
		var allModel []string
		allModel = append(allModel, generateModel(templateStruct))
		err = addInitModel(allModel)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("初始化模型生成失败"))
			return
		}
		config.DbConfig.EnableNeedInitBusiness()
		updateMap := map[string]any{
			"generated": true,
		}
		err := dal.UpdateForMap(&templateStruct, updateMap)
		if logger.HasError(err) {
			c.JSON(http.StatusInternalServerError, core.Err.WithMsg("结构体更新失败"))
			return
		}
	}
	c.JSON(http.StatusOK, core.OK)
}

func generateStructForModel(templateStruct model.TemplateStruct) error {
	path := filepath.Join(ModelPath, tools.CamelToSnake(templateStruct.StructName)+".go")
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()
	err = code.TemplateMap["model"].Execute(file, templateStruct)
	if err != nil {
		return err
	}
	return nil
}

func generateStructForDao(templateStruct model.TemplateStruct) error {
	path := filepath.Join(DaoPath, tools.CamelToSnake(templateStruct.StructName)+"_dao.go")
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()
	err = code.TemplateMap["dao"].Execute(file, templateStruct)
	if err != nil {
		return err
	}
	return nil
}

func generateStructForService(templateStruct model.TemplateStruct) error {
	path := filepath.Join(ServicePath, tools.CamelToSnake(templateStruct.StructName)+"_service.go")
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()
	err = code.TemplateMap["service"].Execute(file, templateStruct)
	if err != nil {
		return err
	}
	return nil
}

func deleteStructAll(templateStruct model.TemplateStruct) error {
	structName := tools.CamelToSnake(templateStruct.StructName)
	paths := []string{
		filepath.Join(ModelPath, structName+"_service.go"),
		filepath.Join(DaoPath, structName+".go"),
		filepath.Join(ServicePath, structName+".go"),
	}
	for _, path := range paths {
		if _, err := os.Stat(path); err != nil {
			if os.IsNotExist(err) {
				continue
			}
			return err
		}

		if err := os.Remove(path); err != nil {
			return err
		}
	}
	return nil
}

func generateRouting(templateStruct model.TemplateStruct) string {
	routerList := tools.LowerFirst(templateStruct.StructName) + `Api := api.Group("/` + tools.LowerFirst(templateStruct.StructName) + `")
		{
			` + tools.LowerFirst(templateStruct.StructName) + `Api.POST("/create", handler.CreateOrUpdate` + templateStruct.StructName + `)
			` + tools.LowerFirst(templateStruct.StructName) + `Api.POST("/update", handler.CreateOrUpdate` + templateStruct.StructName + `)
			` + tools.LowerFirst(templateStruct.StructName) + `Api.POST("/delete", handler.Delete` + templateStruct.StructName + `)
			` + tools.LowerFirst(templateStruct.StructName) + `Api.POST("/page", handler.List` + templateStruct.StructName + `Page)
			` + tools.LowerFirst(templateStruct.StructName) + `Api.POST("/find", handler.Find` + templateStruct.StructName + `ById)
		}`
	return routerList
}

func generateModel(templateStruct model.TemplateStruct) string {
	return `&model.` + templateStruct.StructName + `{},`
}

var routerPath = "biz/router/register.go"
var routerPathTemp = "biz/router/register_temp.go"
var insertPoint = "//INSERT_POINT: DO NOT DELETE THIS LINE!"

func addRouter(routerList []string) error {
	if len(routerList) == 0 {
		return nil
	}
	addString := strings.Join(routerList, "\n")
	file, err := os.Open(routerPath)
	if err != nil {
		return err
	}
	defer file.Close()
	tempFile, err := os.Create(routerPathTemp)
	if err != nil {
		return err
	}
	defer tempFile.Close()
	scanner := bufio.NewScanner(file)
	writer := bufio.NewWriter(tempFile)
	found := false
	for scanner.Scan() {
		line := scanner.Text()
		_, err := writer.WriteString(line + "\n")
		if err != nil {
			return err
		}
		if strings.Contains(line, insertPoint) {
			found = true
			_, err := writer.WriteString(addString + "\n")
			if err != nil {
				return err
			}
		}
	}
	if !found {
		return nil
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	err = writer.Flush()
	if err != nil {
		return err
	}
	err = file.Close()
	if err != nil {
		return err
	}
	err = tempFile.Close()
	if err != nil {
		return err
	}
	err = os.Rename(routerPathTemp, routerPath)
	return nil
}

var modelPath = "biz/dal/init_business_table_data.go"
var modelPathTemp = "biz/dal/init_business_table_data_temp.go"
var importModel = `//"hertz_demo/biz/model"`

func addInitModel(modelList []string) error {
	if len(modelList) == 0 {
		return nil
	}
	addString := strings.Join(modelList, "\n")
	file, err := os.Open(modelPath)
	if err != nil {
		return err
	}
	defer file.Close()
	tempFile, err := os.Create(modelPathTemp)
	if err != nil {
		return err
	}
	defer tempFile.Close()
	scanner := bufio.NewScanner(file)
	writer := bufio.NewWriter(tempFile)
	found := false
	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, importModel) {
			line = strings.Replace(line, "//", "", -1)

		}
		_, err := writer.WriteString(line + "\n")
		if err != nil {
			return err
		}
		if strings.Contains(line, insertPoint) {
			found = true
			_, err := writer.WriteString(addString + "\n")
			if err != nil {
				return err
			}
		}
	}
	if !found {
		return nil
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	err = writer.Flush()
	if err != nil {
		return err
	}
	err = file.Close()
	if err != nil {
		return err
	}
	err = tempFile.Close()
	if err != nil {
		return err
	}
	err = os.Rename(modelPathTemp, modelPath)
	return nil
}
